home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Cream of the Crop 3
/
Cream of the Crop 3.iso
/
comm
/
wnos5src.zip
/
CONVERS.C
< prev
next >
Wrap
Text File
|
1993-08-09
|
21KB
|
875 lines
/* convers server - based on conversd written by DK5SG
* ported to WNOS by DB3FL - 9109xx/9110xx
*/
#include <stdio.h>
#include <string.h>
#include <time.h>
#include <ctype.h>
#include <io.h>
#include "global.h"
#include "config.h"
#ifdef CONVERS
#ifdef MAILBOX
#include "mailbox.h"
#include "netuser.h"
#endif
#include "timer.h"
#include "smtp.h"
#include "cmdparse.h"
#include "socket.h"
#include "session.h"
#include "files.h"
#include "clients.h"
#include "convers.h"
#ifdef LZW
#include "lzw.h"
#endif
char *CHostname = NULLCHAR;
static char near cnumber[] = "*** Channel numbers must be in the range 0..%d.\n";
#define MAXCHANNEL 32766
#define LINELEN 256
#define CBUFLEN 2048
#define MAX_WAITTIME (3 * HOURS)
struct convection {
int type; /* Connection type */
#define CT_UNKNOWN 0
#define CT_USER 1
#define CT_HOST 2
#define CT_CLOSED 3
char name[80]; /* Name of user or host */
char host[80]; /* Name of host where user is logged on */
struct convection *via; /* Pointer to neighbor host */
int channel; /* Channel number */
int32 time; /* Connect time */
int locked; /* Set if mesg already sent */
int fd; /* Socket descriptor */
char *ibuf; /* Input buffer */
int32 received; /* Number of bytes received */
int32 xmitted; /* Number of bytes transmitted */
struct convection *next; /* Linked list pointer */
};
#define CM_UNKNOWN (1 << CT_UNKNOWN)
#define CM_USER (1 << CT_USER)
#define CM_HOST (1 << CT_HOST)
#define CM_CLOSED (1 << CT_CLOSED)
#define NULLCONNECTION ((struct convection *) 0)
static struct convection *convections = NULLCONNECTION;
struct permlink *Permlink = NULLPERMLINK;
static char * near
getarg(char *line,int all)
{
char *arg;
static char *cp;
if (line) {
for (cp = line; *cp; cp++) ;
while (--cp >= line && isspace(*cp & 0xff)) ;
cp[1] = 0;
cp = line;
}
while (isspace(*cp & 0xff)) cp++;
if (all) return cp;
arg = cp;
while (*cp && !isspace(*cp & 0xff)) {
if (*cp >= 'A' && *cp <= 'Z') *cp = tolower(*cp);
cp++;
}
if (*cp) *cp++ = 0;
return arg;
}
static void near
free_connection(struct convection *cp)
{
struct permlink *p;
for (p = Permlink; p; p = p->next)
if (p->convection == cp)
p->convection = NULLCONNECTION;
if (cp->fd)
close_s(cp->fd);
xfree(cp->ibuf);
xfree(cp);
}
static void near
free_closed_connections(void)
{
struct convection *cp, *p;
for (p = NULLCONNECTION, cp = convections; cp; )
if (cp->type == CT_CLOSED
|| cp->type == CT_UNKNOWN
&& cp->time + 300 < currtime) {
if (p) {
p->next = cp->next;
free_connection(cp);
cp = p->next;
} else {
convections = cp->next;
free_connection(cp);
cp = convections;
}
} else {
p = cp;
cp = cp->next;
}
}
static void near
update_Permlink(char *name,struct convection *cp)
{
struct permlink *p;
for(p = Permlink; p; p = p->next)
if(!strcmp(p->name, name)) {
p->convection = cp;
p->statetime = currtime;
p->tries = 0;
p->waittime = 60;
p->retrytime = currtime + p->waittime;
}
}
static struct convection * near
alloc_connection(int fd)
{
struct convection *cp = mxallocw(sizeof(struct convection));
cp->next = convections;
convections = cp;
cp->fd = fd;
cp->time = currtime;
cp->ibuf = mxallocw(CBUFLEN);
return cp;
}
#ifdef LINK
void
connect_Permlink(int a,void *b,void *c)
{
FILE *fp;
char *cp, line[LINELEN];
struct permlink *p;
if(CHostname == NULLCHAR) {
CHostname = strxdup(Hostname);
if((cp = strchr(CHostname,'.')) != NULLCHAR) {
*cp = '\0';
}
}
sprintf(line,"%s/convers.cfg",EtcRoot);
if((fp = Fopen(line,READ_TEXT,0,0)) != NULLFILE) {
while(fgets(line,LINELEN,fp)) {
if(*line == '#') {
continue;
}
p = mxallocw(sizeof(struct permlink));
sscanf(line,"%38s %18s %18s",p->name,p->link_info,p->command);
if(*p->link_info) {
p->next = Permlink;
Permlink = p;
} else {
xfree(p);
}
}
Fclose(fp);
}
if(Permlink) {
int s, x;
struct sockaddr_in cport;
for(;;) {
pause(2000L);
for (p = Permlink; p; p = p->next) {
if (p->convection || p->retrytime > currtime) continue;
p->tries++;
p->waittime <<= 1;
if (p->waittime > MAX_WAITTIME) p->waittime = MAX_WAITTIME;
p->retrytime = p->waittime + currtime;
x = 0;
switch(tolower(*p->link_info)) {
case 'x': /* compressed telnet connection */
x = 1;
case 't': /* telnet connection */
cport.sin_family = AF_INET;
cport.sin_port = x ? IPPORT_XCONVERS : IPPORT_CONVERS;
if((cport.sin_addr.s_addr = resolve(p->name)) != 0) {
if((s = socket(AF_INET,SOCK_STREAM,0)) != -1) {
if(connect(s,(char *)&cport,SOCKSIZE) != -1) {
p->fd = s;
sockmode(p->fd,SOCK_BINARY);
newproc("permlink",2048,conv_incom,s,(void *)x,NULL,0);
} else {
close_s(s);
}
}
}
break;
/* case 'a': ax25 connection */
/* case 'n': netrom connection */
/* default: */
/* continue; */
}
}
}
}
}
#endif
static void near
clear_locks(void)
{
struct convection *p;
for (p = convections; p; p = p->next) p->locked = 0;
}
static void
send_user_change_msg(char *name,char *host,int oldchannel,int newchannel)
{
struct convection *p;
for (p = convections; p; p = p->next) {
if (p->type == CT_USER && !p->via && !p->locked) {
if (p->channel == oldchannel) {
if (newchannel >= 0)
p->xmitted += usprintf(p->fd, "*** %s switched to channel %d.\n", name, newchannel);
else
p->xmitted += usprintf(p->fd, "*** %s signed off.\n", name);
p->locked = 1;
}
if (p->channel == newchannel) {
p->xmitted += usprintf(p->fd, "*** %s signed on.\n", name);
p->locked = 1;
}
}
if (p->type == CT_HOST && !p->locked) {
p->xmitted += usprintf(p->fd,"/\377\200USER %s %s 0 %d %d\n",
name, host, oldchannel, newchannel);
p->locked = 1;
}
}
return;
}
static char * near
timestring(int32 gmt)
{
static char buffer[10];
struct tm *tm = localtime(&gmt);
if (gmt + 86400L > currtime) {
sprintf(buffer," %2d:%02d",tm->tm_hour,tm->tm_min);
} else {
sprintf(buffer,"%-3.3s %2d",Months[tm->tm_mon - 1],tm->tm_mday);
}
return buffer;
}
static char *
formatline(char *prefix,char *text)
{
#define PREFIXLEN 10
#define CONVLINELEN 79
char *f, *t, *x;
static char buf[2048];
int l, lw;
for (f = prefix, t = buf; *f; *t++ = *f++) ;
l = (int)(t - buf);
f = text;
for (; ; ) {
while (isspace(uchar(*f))) f++;
if (!*f) {
*t++ = '\n';
*t = '\0';
return buf;
}
for (x = f; *x && !isspace(uchar(*x)); x++) ;
lw = (int)(x - f);
if (l > PREFIXLEN && l + 1 + lw > CONVLINELEN) {
*t++ = '\n';
l = 0;
}
do {
*t++ = ' ';
l++;
} while (l < PREFIXLEN);
while (lw--) {
*t++ = *f++;
l++;
}
}
}
static void
send_msg_to_user(char *fromname,char *toname,char *text)
{
struct convection *p;
char *buffer = mxallocw(CBUFLEN);
for (p = convections; p; p = p->next) {
if (p->type == CT_USER && !strcmp(p->name, toname))
if (p->via) {
if (!p->via->locked) {
p->via->xmitted += usprintf(p->via->fd,
"/\377\200UMSG %s %s %s\n", fromname, toname, text);
p->via->locked = 1;
}
} else {
if (!p->locked) {
if (strcmp(fromname, "conversd")) {
sprintf(buffer, "<*%s*>:", fromname);
p->xmitted += usprintf(p->fd,"%s",formatline(buffer, text));
} else {
p->xmitted += usprintf(p->fd,"%s\n",text);
}
p->locked = 1;
}
}
}
xfree(buffer);
return;
}
static void
send_msg_to_channel(char *fromname,int channel,char *text)
{
struct convection *p;
char *buffer = mxallocw(CBUFLEN);
for (p = convections; p; p = p->next) {
if (p->type == CT_USER && p->channel == channel) {
if (p->via) {
if (!p->via->locked) {
p->via->xmitted += usprintf(p->via->fd,
"/\377\200CMSG %s %d %s\n", fromname, channel, text);
p->via->locked = 1;
}
} else {
if (!p->locked) {
sprintf(buffer, "<%s>:", fromname);
p->xmitted += usprintf(p->fd,"%s",formatline(&buffer[0],text));
p->locked = 1;
}
}
}
}
xfree(buffer);
return;
}
static void
send_invite_msg(char *fromname,char *toname,int channel)
{
static char invitetext[] = "\n\007\007*** Message from %s at%s ...\nPlease join convers channel %d.\n\007\007\n";
static char responsetext[] = "*** Invitation sent to %s @ %s";
static char cnvd[] = "conversd";
char *buffer = mxallocw(CBUFLEN);
struct convection *p;
#ifdef MAILBOX
struct mbx *m;
#endif
for (p = convections; p; p = p->next) {
#ifdef MAILBOX
for(m = Mbox; m != NULLMBX; m = m->next) {
if(m->state == MBX_CMD && !strcmp(m->name,toname)) {
p->xmitted += usprintf(m->user,invitetext,fromname,timestring(currtime), channel);
usflush(m->user);
clear_locks();
sprintf(buffer, responsetext, toname, "LocBBS@");
strcat(buffer,CHostname);
send_msg_to_user(cnvd, fromname, buffer);
xfree(buffer);
return;
}
}
#endif
if (p->type == CT_USER && !strcmp(p->name, toname)) {
if (p->channel == channel) {
clear_locks();
sprintf(buffer, "*** User %s is already on this channel.", toname);
send_msg_to_user(cnvd, fromname, buffer);
xfree(buffer);
return;
}
if (!p->via && !p->locked) {
p->xmitted += usprintf(p->fd,invitetext,fromname,timestring(currtime),channel);
clear_locks();
sprintf(buffer, responsetext, toname, CHostname);
send_msg_to_user(cnvd, fromname, buffer);
xfree(buffer);
return;
}
if (p->via && !p->via->locked) {
p->via->xmitted += usprintf(p->via->fd,
"/\377\200INVI %s %s %d\n", fromname, toname, channel);
xfree(buffer);
return;
}
}
}
for (p = convections; p; p = p->next) {
if (p->type == CT_HOST && !p->locked) {
p->xmitted += usprintf(p->fd,
"/\377\200INVI %s %s %d\n", fromname, toname, channel);
}
}
xfree(buffer);
return;
}
static void near
bye_command(struct convection *cp)
{
struct convection *p;
int oldtype = cp->type;
cp->type = CT_CLOSED;
switch(oldtype) {
case CT_USER:
clear_locks();
send_user_change_msg(cp->name,cp->host,cp->channel,-1);
break;
case CT_HOST:
update_Permlink(cp->name, NULLCONNECTION);
for (p = convections; p; p = p->next) {
if (p->via == cp) {
p->type = CT_CLOSED;
clear_locks();
send_user_change_msg(p->name,p->host,p->channel,-1);
}
}
break;
}
}
static void near
channel_command(struct convection *cp)
{
int newchannel;
char *s = getarg(0,0);
if (!*s) {
cp->xmitted += usprintf(cp->fd,"*** You are on channel %d.\n",cp->channel);
return;
}
newchannel = atoi(s);
if (newchannel < 0 || newchannel > MAXCHANNEL) {
cp->xmitted += usprintf(cp->fd,cnumber,MAXCHANNEL);
return;
}
if (newchannel == cp->channel) {
cp->xmitted += usprintf(cp->fd,
"*** Already on channel %d.\n", cp->channel);
return;
}
send_user_change_msg(cp->name, cp->host, cp->channel, newchannel);
cp->channel = newchannel;
cp->xmitted += usprintf(cp->fd, "*** Now on channel %d.\n", cp->channel);
return;
}
static void near
help_command(struct convection *cp)
{
char *cp1 = getarg(0,1);
if(!(*(cp1))) {
cp->xmitted += usputs(cp->fd,"Commands may be abbreviated. Commands are:\n"
"/bye /channel /exit /help /invite\n"
"/links /msg /quit /who /write\n");
} else {
gethelp(IPPORT_CONVERS,cp->fd,cp1);
}
}
static void near
invite_command(struct convection *cp)
{
char *toname = getarg(0,0);
if (*toname) send_invite_msg(cp->name, toname, cp->channel);
}
static void near
links_command(struct convection *cp)
{
char tmp[20];
struct convection *pc;
struct permlink *pp;
int full = *(getarg(0,0));
cp->xmitted += usprintf(cp->fd,"Host State Since%s\n",
full ? " NextTry Tries Queue Receivd Xmitted" : "");
for(pc = convections; pc; pc = pc->next) {
if(pc->type == CT_HOST) {
cp->xmitted += usprintf(cp->fd,
full ?
"%-8.8s %-12s %s%15d %7d %7d\n" :
"%-8.8s %-12s %s\n",
pc->name,
"Connected",
timestring(pc->time),
0, /* always 0, cuz NOS handles the tx-queue */
pc->received,
pc->xmitted);
}
}
for(pp = Permlink; pp; pp = pp->next) {
if(!pp->convection || pp->convection->type != CT_HOST) {
strcpy(tmp,timestring(pp->retrytime)),
cp->xmitted += usprintf(cp->fd,
full ?
"%-8.8s %-12s %s %s %5d\n" :
"%-8.8s %-12s %s\n",
pp->name,
pp->convection ? "Connecting" : "Disconnected",
timestring(pp->statetime),
tmp,
pp->tries);
}
}
cp->xmitted += usputs(cp->fd,"***\n");
return;
}
static void near
msg_command(struct convection *cp)
{
struct convection *p;
char *toname = getarg(0,0);
char *text = getarg(0,1);
if (!*text) return;
for (p = convections; p; p = p->next)
if (p->type == CT_USER && !strcmp(p->name, toname))
break;
if (!p)
cp->xmitted += usprintf(cp->fd, "*** No such user: %s.\n", toname);
else
send_msg_to_user(cp->name, toname, text);
return;
}
static void near
name_command(struct convection *cp)
{
int newchannel;
char *s = getarg(0,0);
if(!*s)
return;
sprintf(cp->name,"%.79s",s);
strlwr(cp->name);
cp->type = CT_USER;
sprintf(cp->host,"%.79s",CHostname);
cp->xmitted += usprintf(cp->fd,
"conversd @ %s $ Rev: 2.17 (WNOS.5) $ Type /HELP for help.\n", CHostname);
newchannel = atoi(getarg(0,0));
if (newchannel < 0 || newchannel > MAXCHANNEL) {
cp->xmitted += usprintf(cp->fd,cnumber,MAXCHANNEL);
} else
cp->channel = newchannel;
send_user_change_msg(cp->name, cp->host, -1, cp->channel);
return;
}
static void near
who_command(struct convection *cp)
{
int channel, full = 0, quick = 0;
struct convection *p;
#ifdef MAILBOX
struct mbx *m;
#endif
char *buffer = mxallocw(CBUFLEN);
switch(*(getarg(0,0))) {
case 'l':
full = 1;
break;
case 'q':
quick = 1;
break;
}
if (quick) {
cp->xmitted += usputs(cp->fd, "Channel Users\n");
clear_locks();
do {
channel = -1;
for (p = convections; p; p = p->next) {
if (p->type == CT_USER && !p->locked && (channel < 0 || channel == p->channel)) {
if (channel < 0) {
channel = p->channel;
sprintf(buffer, "%7d", channel);
}
strcat(buffer, " ");
strcat(buffer, p->name);
p->locked = 1;
}
}
if (channel >= 0) {
cp->xmitted += usprintf(cp->fd, "%s\n",buffer);
}
} while (channel >= 0);
} else {
cp->xmitted += usprintf(cp->fd,
"User Host Via Channel Time%s\n",
full ? " HQueue Receivd Xmitted" : "");
for (p = convections; p; p = p->next) {
if (p->type == CT_USER) {
cp->xmitted += usprintf(cp->fd,"%-8.8s %-8.8s %-8.8s %7d %s",
p->name,
p->host,
p->via ? p->via->name : "",
p->channel,
timestring(p->time));
if(full)
cp->xmitted += usprintf(cp->fd,"%7d %7d %7d",
0, /* always 0 cuz NOS handles the tx-queue */
p->received,
p->xmitted);
cp->xmitted += usputs(cp->fd,"\n");
}
}
}
#ifdef MAILBOX
for(m = Mbox; m != NULLMBX; m = m->next) {
if(m->state == MBX_CMD) {
if(quick)
cp->xmitted += usprintf(cp->fd," LocBBS %s\n",m->name);
else
cp->xmitted += usprintf(cp->fd,"%-8s LocBBS@%s\n",m->name,CHostname);
}
}
#endif
cp->xmitted += usputs(cp->fd, "***\n");
xfree(buffer);
return;
}
static void near
h_cmsg_command(struct convection *cp)
{
char *name = getarg(0, 0);
int channel = atoi(getarg(0, 0));
char *text = getarg(0, 1);
if (*text) send_msg_to_channel(name,channel,text);
}
static void near
h_host_command(struct convection *cp)
{
struct convection *p;
struct permlink *pp;
char *name = getarg(0,0);
if (!*name) return;
for (p = convections; p; p = p->next)
if (!strcmp(p->name, name)) bye_command(p);
for (pp = Permlink; pp; pp = pp->next)
if (!strcmp(pp->name, name) && pp->convection && pp->convection != cp)
bye_command((strcmp(CHostname, name) < 0) ? pp->convection : cp);
if (cp->type != CT_UNKNOWN) return;
cp->type = CT_HOST;
strcpy(cp->name,name); /* already allocated */
update_Permlink(name, cp);
cp->xmitted += usprintf(cp->fd, "/\377\200HOST %s\n", CHostname);
for (p = convections; p; p = p->next)
if (p->type == CT_USER) {
cp->xmitted += usprintf(cp->fd,
"/\377\200USER %s %s 0 -1 %d\n", p->name, p->host, p->channel);
}
return;
}
static void near
h_invi_command(struct convection *cp)
{
char *fromname = getarg(0,0);
char *toname = getarg(0,0);
int channel = atoi(getarg(0,0));
send_invite_msg(fromname, toname, channel);
}
static void near
h_umsg_command(struct convection *cp)
{
char *fromname = getarg(0, 0);
char *toname = getarg(0, 0);
char *text = getarg(0, 1);
if (*text) send_msg_to_user(fromname, toname, text);
}
static void near
h_user_command(struct convection *cp)
{
int oldchannel, newchannel;
struct convection *p;
char *name = getarg(0, 0);
char *host = getarg(0, 0);
getarg(0, 0); /*** ignore this argument, protocol has changed ***/
oldchannel = atoi(getarg(0, 0));
newchannel = atoi(getarg(0, 0));
for (p = convections; p; p = p->next)
if (p->type == CT_USER &&
p->channel == oldchannel &&
p->via == cp &&
!strcmp(p->name, name) &&
!strcmp(p->host, host)) break;
if (!p) {
p = mxallocw(sizeof(struct convection));
p->type = CT_USER;
sprintf(p->name,"%.79s",name);
sprintf(p->host,"%.79s",host);
p->via = cp;
p->channel = oldchannel;
p->time = currtime;
p->next = convections;
convections = p;
}
if ((p->channel = newchannel) < 0) p->type = CT_CLOSED;
send_user_change_msg(name, host, oldchannel, newchannel);
}
/* Incoming convers session */
void
conv_incom(int s,void *t,void *p)
{
struct convection *cp;
struct permlink *pl;
char *arg;
int size;
static struct cmdtable {
char *name;
void near (*func) __ARGS((struct convection *cp));
int states;
} cmdtable[] = {
"?", help_command, CM_USER,
"bye", bye_command, CM_USER,
"channel", channel_command, CM_USER,
"exit", bye_command, CM_USER,
"help", help_command, CM_USER,
"invite", invite_command, CM_USER,
"links", links_command, CM_USER,
"msg", msg_command, CM_USER,
"name", name_command, CM_UNKNOWN,
"quit", bye_command, CM_USER,
"who", who_command, CM_USER,
"write", msg_command, CM_USER,
"\377\200cmsg", h_cmsg_command, CM_HOST,
"\377\200host", h_host_command, CM_UNKNOWN,
"\377\200invi", h_invi_command, CM_HOST,
"\377\200umsg", h_umsg_command, CM_HOST,
"\377\200user", h_user_command, CM_HOST,
0, 0, 0,
};
struct cmdtable *cmdp;
sockowner(s,Curproc); /* We own it now */
cp = alloc_connection(s);
#ifdef LZW
if((int)t == 1) {
lzwinit(s,Lzwbits,Lzwmode);
}
#endif
for(pl = Permlink; pl; pl = pl->next) {
if(pl->fd == s) {
pl->convection = cp;
if(pl->command != NULLCHAR) {
usprintf(s,"%s\n",pl->command);
}
cp->xmitted += usprintf(s, "/\377\200HOST %s\n", CHostname);
}
}
if(pl == NULLPERMLINK) {
usputs(cp->fd,"\n*** pse login with '/n <call>'\n\n");
}
for (; ; ) {
loop:
if(cp->type == CT_CLOSED) {
break;
}
if((size = recvline(cp->fd,cp->ibuf,CBUFLEN)) <= 0) {
bye_command(cp);
break;
}
cp->received += size;
clear_locks();
cp->locked = 1;
rip(cp->ibuf);
if(*cp->ibuf == '/') {
int arglen = strlen(arg = getarg(cp->ibuf + 1, 0));
for(cmdp = cmdtable; cmdp->name; cmdp++) {
if(!strnicmp(cmdp->name,arg,arglen)) {
if(cmdp->states & (1 << cp->type)) {
(*cmdp->func)(cp);
}
goto loop;
}
}
if(cp->type == CT_USER) {
cp->xmitted += usprintf(cp->fd,
"*** Unknown command '/%s'. Type /HELP for help.\n", arg);
}
goto loop;
}
if(isprint(*cp->ibuf) != 0 && cp->type == CT_USER) {
send_msg_to_channel(cp->name, cp->channel, cp->ibuf);
}
}
free_closed_connections();
return;
}
#endif /* CONVERS */